﻿using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using UIOC.CodeAnalysis.Diagnostics;
using UIOC.CodeAnalysis.Extensions;

namespace UIOC.CodeAnalysis.Analyzers;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class InstantiationAnalyzer : DiagnosticAnalyzer {

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
        => ImmutableArray.Create(InstantiationDiagnostic.Rule);

    public override void Initialize(AnalysisContext context) {
        context.EnableConcurrentExecution();
        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
        context.RegisterSyntaxNodeAction(AnalyzeObjectCreation, SyntaxKind.ObjectCreationExpression);
    }

    private void AnalyzeObjectCreation(SyntaxNodeAnalysisContext context) {
        var compilation = context.Compilation;
        var assembly = compilation.Assembly;
        if (assembly.IsIgnore()) {
            return;
        }

        if (context.Node is not ObjectCreationExpressionSyntax objectCreationExpressionSyntax) {
            return;
        }

        if (context.SemanticModel.GetTypeInfo(objectCreationExpressionSyntax).Type is not INamedTypeSymbol objectSymbol) {
            return;
        }

        var objectInterfaceSymbol = compilation.GetTypeByMetadataName(TypeFullNames.IObject);
        if (objectInterfaceSymbol == null) {
            return;
        }

        if (objectSymbol.AllInterfaces.Contains(objectInterfaceSymbol, SymbolEqualityComparer.Default)) {
            context.ReportDiagnostic(Diagnostic.Create(
                InstantiationDiagnostic.Rule,
                objectCreationExpressionSyntax.Type.GetLocation(),
                objectSymbol.GetShortName()
            ));
        }
    }
}
